using System;
using System.Collections;
using System.Collections.Generic;
using MonsterLove.StateMachine;
using Platform;
using Platform.CharacterData;
using Platform.Skill.Core;
using UnityEngine;
using Plugin.Tool;
using BehaviorDesigner.Runtime.Tasks.Unity.UnityTransform;
using Pixelplacement;
using Cysharp.Threading.Tasks;
using System.Threading;
using cfg;

// 拖拽组件会自动导入CharacterStats，之后直接在awake获取，解除依赖
[RequireComponent(typeof(CharacterStats))]
public class Entity : MonoBehaviour
{
    //  半代码控制动画
    //约定动画名就是枚举名
    public enum States
    {
        None,
        Idle,
        Move,
        AirState,
        Dash,
        WallSlide,
        /// <summary>
        /// 轻连击
        /// </summary>
        LightDoubleAttack,
        HeavyDoubleAttack,
        /// <summary>
        /// 反击
        /// </summary>
        CounterAttack,
        Die,
        OnHit,

        Blackhole,//空状态

        // 剑瞄准
        AimSword,
        ThrowSword,
        CatchSword,

        #region 敌人状态
        Battle,//空状态
        Stunned,

        #endregion
    }
    public StateMachine<States, EntityDriver> fsm;
    public virtual void ChangeState(States newState, bool isBreakAnimation = false)
    {
        fsm.ChangeState(newState, isBreakAnimation);
        HandleStateChange(newState, isBreakAnimation);
    }
    public States CurrentState => fsm.CurrentState;

    #region  基础组件
    public Animator anim { get; private set; }
    public Rigidbody2D rb { get; private set; }
    public SpriteRenderer sr { get; private set; }
    public CapsuleCollider2D cd { get; private set; }
    #endregion

    #region 角色数据
    public CharacterStats stats;

    #endregion

    #region  基础数据
    public float JumpHeight => stats.jumpHeight.Value;
    #endregion

    #region 攻击
    public Collider2D attackCheckCollider;
    public int lightDoubleAttackCombo;
    public int heavyDoubleAttackCombo;
    protected int lightDoubleAttackComboMax;
    protected int heavyDoubleAttackComboMax;
    [Header("Attack Info")]
    protected float lastAttackTime;
    protected float comboWindow = 5f;//连击窗口，超过这个时间，连击就会中断


    #endregion

    #region  受击
    //硬直
    protected bool isFrozenTime = false;

    protected float StunDuration => stats.stunDuration.Value;
    protected Vector2 StunDirection => stats.stunDirection;
    protected GameObject CounterImg => stats.counterImg;
    protected bool canBeStunnned;
    #endregion

    #region  限制
    protected bool isLockMove;
    #endregion

    #region  碰撞针
    [Header("碰撞针")]

    [SerializeField] protected Transform groundCheck;
    [SerializeField] protected float groundCheckDistance = 0.2f;
    [SerializeField] protected Transform wallCheck;
    [SerializeField] protected float wallCheckDistance = 0.2f;
    protected LayerMask groundLayer;
    protected LayerMask enemyLayer;
    protected LayerMask playerLayer;


    // public bool IsGroundDetected() => Physics2D.BoxCast(groundCheck.position, new Vector2(groundCheckWidth, 0.5f), 0, Vector2.down, groundCheckDistance, groundLayer);
    public virtual bool IsGroundDetected() => Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, groundLayer);
    public bool IsWallDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, groundLayer);

    // 默认情况下就会在编辑模式下运行
    protected virtual void OnDrawGizmos()
    {
        // Vector3 boxCenter = groundCheck.position + Vector3.down * groundCheckDistance / 2;
        // Gizmos.DrawCube(boxCenter, new Vector3(groundCheckWidth, groundCheckDistance, 0));
        Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));//绘制一条从 from(前面的) 开始到 to（后面的） 的线。
        Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));//绘制一条从 from(前面的) 开始到 to（后面的） 的线。

        // if (stats == null) return;
        // Gizmos.color = Color.red;
        // var attackRange = stats.attackRangeDict.ContainsKey(States.PrimaryAttack) ? stats.attackRangeDict?[States.PrimaryAttack]?[ComboCounter] : new AttackRange();

        // Vector3 center = (Vector3)attackRange.Offset;
        // // 设置 Gizmos 的变换矩阵
        // Matrix4x4 oldMatrix = Gizmos.matrix;
        // Gizmos.matrix = Matrix4x4.TRS(center, Quaternion.Euler(0, 0, attackRange.rotation), Vector3.one);
        // Gizmos.DrawWireCube(transform.position + (Vector3)attackRange.Offset, (Vector3)attackRange.Size);
        // // 恢复原来的矩阵
        // Gizmos.matrix = oldMatrix;
    }


    /// <summary>
    /// 射线函数重载  自动变色
    /// </summary>
    public RaycastHit2D Raycast(Vector2 startPos, Vector2 rayDiraction, float length, LayerMask layer)
    {
        RaycastHit2D hit = Physics2D.Raycast(startPos, rayDiraction, length, layer);
        Color color = hit ? Color.red : Color.green;
        Debug.DrawRay(startPos, rayDiraction * length, color);
        return hit;
    }

    #endregion


    #region  方向
    //方向
    public int facingDir = 1;
    public bool facingRight = true;
    #endregion



    #region  特效
    protected EntityFX fx;

    #endregion



    #region  技能
    [Header("技能")]
    public SkillData currentSkillData;
    [HideInInspector] public SkillMgr skillMgr;


    [Header("Dash Info")]
    [SerializeField] protected float dashSpeed = 25;
    protected float dashDir;
    [SerializeField] protected float dashDuration = 0.3f;//持续时间
    protected float dashTimer = 0f;

    [Header("冲刺残影")]
    [SerializeField] private GameObject afterImagePre;
    #endregion



    #region  事件
    public event Action OnFlip;
    protected HashSet<CancellationTokenSource> tempTokenSources = new();
    #endregion




    #region  处理素材
    [Header("特殊处理素材")]
    //特殊处理美术素材问题，也就是图片离原点偏移距离
    public Vector3 spriteOffset;
    #endregion





    #region 生命周期

    protected virtual void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        sr = GetComponentInChildren<SpriteRenderer>();
        cd = GetComponent<CapsuleCollider2D>();

        attackCheckCollider = transform.GetChild(0).GetComponentInChildren<CapsuleCollider2D>();

        stats = GetComponent<CharacterStats>();
        anim = GetComponentInChildren<Animator>();
        anim.runtimeAnimatorController = stats.animController;

        skillMgr = gameObject.GetComponent<SkillMgr>();
        if (skillMgr != null) skillMgr.skillDataList = stats.skillDataList;

        fx = GetComponent<EntityFX>();

        groundLayer = LayerMask.GetMask("Ground");
        enemyLayer = LayerMask.GetMask("Enemy");
        playerLayer = LayerMask.GetMask("Player");

        SetMaxComboCount();
    }
    protected virtual void Start()
    {
        fsm = new StateMachine<States, EntityDriver>(this, true);
        fsm.ChangeState(States.Idle);//立即调用enter
        fsm.OnTriggerAnimationEnd += OnTriggerAnimationEnd;
    }
    protected virtual void OnDestroy()
    {
        fsm.OnTriggerAnimationEnd -= OnTriggerAnimationEnd;
    }

    // Update is called once per frame
    protected virtual void Update()
    {
        //手动执行驱动器   
        fsm.Driver.Update.Invoke();
        // debug
        anim.SetFloat("FaceDir", facingDir);
    }
    protected virtual void FixedUpdate()
    {
        fsm.Driver.FixedUpdate.Invoke();
    }


    #region  状态改变、强制退出
    /// <summary>
    /// 统一进行强制退出动画时处理
    /// </summary>
    private void OnBreakAnimation()
    {
        foreach (var token in tempTokenSources)
        {
            token.Cancel();
        }
        tempTokenSources.Clear();
    }

    /// <summary>
    /// 状态切换统一处理  用正常状态机就不需要
    /// </summary>
    /// <param name="newState"></param>
    protected virtual void HandleStateChange(States newState, bool isBreakAnimation = false)
    {
        // 设置参数  如果打断，则直接播放
        if (isBreakAnimation)
        {
            // 约定状态名和动画名一致
            anim.Play(newState.ToString(), -1, 0f);
            OnBreakAnimation();
        }

        // 处理 当前打击特效 和 伤害类型
        if (newState == States.LightDoubleAttack)
        {
            SetCurrentAttackDamageTypeAndHitEffect(stats.lightAttackDamageType);
        }
        else if (newState == States.HeavyDoubleAttack)
        {
            SetCurrentAttackDamageTypeAndHitEffect(stats.heavyAttackDamageType);
        }
    }

    private void SetCurrentAttackDamageTypeAndHitEffect(AttackDamageType attackDamageType)
    {
        stats.currentAttackDamageType = attackDamageType;
        // stats.currentHitEffect = stats.lightHitEffect;
        switch (attackDamageType)
        {
            case AttackDamageType.Cut:
                stats.currentHitEffect = HitEffect.NormalImpact;
                break;
            case AttackDamageType.Blunt:
                stats.currentHitEffect = HitEffect.NormalExplode;
                break;
            case AttackDamageType.Pierece:
                stats.currentHitEffect = HitEffect.NormalCutLine;
                break;
            case AttackDamageType.Stab:
                stats.currentHitEffect = HitEffect.NormalCutCross;
                break;
        }
    }

    private void OnTriggerAnimationEnd()
    {
        ChangeState(States.Idle);
    }
    #endregion

    #endregion

    #region  行为
    /// <summary>
    /// 直接改变速度
    /// </summary>
    /// <param name="_xVelocity"></param>
    /// <param name="_yVelocity"></param>
    protected virtual void SetVelocity(float _xVelocity, float _yVelocity = 0)
    {
        if (isLockMove) return;
        if (isFrozenTime) return;
        rb.velocity = new Vector2(_xVelocity, _yVelocity);//将rb的velocity属性设置为对应的想要的二维向量。因为2D游戏的速度就是二维向量
        FlipController(_xVelocity);
    }

    public void ZeroVelocity()
    {
        SetVelocity(0, 0);
    }

    public void Flip()
    {
        facingRight = !facingRight;
        facingDir = facingRight ? 1 : -1;
        transform.Rotate(0, 180, 0);
        // GetComponentInChildren<SpriteRenderer>().flipX = !facingRight;
        OnFlip?.Invoke();
    }
    public void FlipController(float _x)
    {
        //当速度和方向有冲突，翻转
        if ((_x > 0 && !facingRight) || (_x < 0 && facingRight))
        {
            Flip();
        }
    }

    #endregion

    #region 动画事件

    public virtual void animationFinishTrigger()
    {
        fsm.Driver.AnimationFinishTrigger.Invoke();
    }
    // public virtual void AttackTrigger() { }
    public virtual void AttackTrigger(Collider2D other)
    {
        AttackColliderCheck<Entity>(other, (entity) => entity.BeDamage(stats, other));

        //顿帧和震动   boss可能也有
        switch (CurrentState)
        {
            case States.LightDoubleAttack:
                CameraMgr.Instance.TriggerScreenShake(LightShakePower);
                //顿帧
                CameraMgr.Instance.TriggerTimeFreeze(stats.lightFreaze);
                // CameraMgr.Instance.TriggerLocalTimeFreeze(anim,stats.lightFreaze);
                break;
            case States.HeavyDoubleAttack:
                CameraMgr.Instance.TriggerScreenShake(HeavyShakePower);
                CameraMgr.Instance.TriggerTimeFreeze(stats.heavyFreaze);
                // CameraMgr.Instance.TriggerLocalTimeFreeze(anim,stats.heavyFreaze);
                break;
            case States.CounterAttack:
                CameraMgr.Instance.TriggerScreenShake(HeavyShakePower);
                CameraMgr.Instance.TriggerTimeFreeze(stats.heavyFreaze);
                // CameraMgr.Instance.TriggerLocalTimeFreeze(anim,stats.heavyFreaze);
                break;
            default:
                break;
        }
    }

    #endregion


    #region  攻击相关
    /// <summary>
    /// 攻击检测
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="action"></param>
    protected void AttackColliderCheck<T>(Collider2D other, Action<T> action) where T : Entity
    {
        if (other.TryGetComponent(out T entity))
        {
            action?.Invoke(entity);
        }
    }
    protected virtual void AttackCheckFront<T>(Action<T> action) where T : Entity
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position + Vector3.right * facingDir * 0.3f, 0.6f);
        foreach (Collider2D hit in colliders)
        {
            if (hit.TryGetComponent<T>(out T entity))
            {
                action?.Invoke(entity);
            }
        }
    }
    protected virtual void AttackCheckFrontAll<T>(Action<List<T>> action) where T : Entity
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position + Vector3.right * facingDir * 0.3f, 0.6f);
        List<T> list = new List<T>();
        foreach (Collider2D hit in colliders)
        {
            if (hit.TryGetComponent<T>(out T entity))
            {
                list.Add(entity);
            }
        }
        action?.Invoke(list);
    }
    // protected void AttackColliderCheck<T>(Action<T> action) where T : Entity
    // {
    // AttackRange attackRange = stats.attackRangeDict[States.PrimaryAttack][ComboCounter];
    // var offset = facingRight ? attackRange.offset.ToVector2() : new Vector2(-attackRange.offset.x, attackRange.offset.y);
    // var rotation = facingRight ? attackRange.rotation : -attackRange.rotation;

    // Collider2D[] colliders = Physics2D.OverlapBoxAll(offset, attackRange.size.ToVector2(), rotation);

    // foreach (Collider2D hit in colliders)
    // {
    //     if (hit.TryGetComponent<T>(out T entity))
    //     {
    //         action?.Invoke(entity);
    //     }
    // }
    // }
    #endregion


    #region  受击
    public virtual void Die()
    {
        ChangeState(States.Die);
        //人族暴血
        if (stats.IsLivingBody)
        {
            EffectMgr.Instance.AddWorldEffect(Settings.BloodImpacttEffect, Tool.GetEntityCenterByCollider(transform));
            EffectMgr.Instance.AddWorldEffect(BloodParticleType.Big, Tool.GetEntityCenterByCollider(transform));
        }
    }
    public virtual void BeDamage(CharacterStats source, Collider2D other = null)
    {
        stats.BeDamage(source, other);
    }
    public virtual void BeDamage(CharacterStats source, int damage, DamageType damageType)
    {
        stats.BeDamage(source, damage, damageType);
    }
    // todo 削韧才触发
    public virtual void OnHit(CharacterStats sourceStats)
    {
        // 目前仅普通攻击触发
        if (stats.beCrit)
            sourceStats.fx.CreateHit(sourceStats.entity.attackCheckCollider, stats, true);
        else
            sourceStats.fx.CreateHit(sourceStats.entity.attackCheckCollider, stats);

        // 有受击动画就不闪白   
        if (HasStateAnim(States.OnHit))
        {
            ChangeState(States.OnHit, true);
            // anim.Play("OnHit", -1, 0f);
        }
        else
            fx.FlashFX();

        BeBattleBack(sourceStats.transform, sourceStats.knockBackForce, sourceStats.knockBackPower.Value);
    }
    /// <summary>
    /// 被击退
    /// </summary>
    /// <param name="other">来源</param>
    /// <param name="knockBackForce">方向与力量</param>
    /// <param name="knockbackPower">力量修正</param>
    public void BeBattleBack(Transform other, Vector2 knockBackForce, float knockbackPower = 1)
    {
        if (knockBackForce == Vector2.zero) return;
        var dir = other.position.x > transform.position.x ? -1 : 1;
        // 锁移动，固定的击退效果
        StartCoroutine(LockMoveAsync(0.5f));

        rb.velocity = new Vector2(knockBackForce.x * dir * knockbackPower, knockBackForce.y * knockbackPower);
    }
    /// <summary>
    /// 锁移动：直到落地
    /// </summary>
    /// <param name="time"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    protected IEnumerator LockMoveAsync(float time)
    {
        isLockMove = true;
        yield return new WaitForSeconds(time);
        yield return new WaitUntil(() => IsGroundDetected());
        isLockMove = false;
    }


    #endregion


    #region  技能
    public void MakeTransparent(bool transparent)
    {
        sr.color = new Color(1, 1, 1, transparent ? 0 : 1);
    }

    public virtual bool TryUseSkill(out SkillData skillData, SkillEnum _skill, Vector3 targetPos = default)
    {
        skillData = skillMgr.UseSkill(_skill, targetPos);
        return skillData != null;
    }
    public bool TryUseSkill(SkillEnum _skill, Vector3 targetPos = default) => TryUseSkill(out SkillData skillData, _skill, targetPos);
    public SkillData UseSkill(SkillEnum _skill, Vector3 targetPos = default) => skillMgr.UseSkill(_skill, targetPos);


    #endregion

    #region 通用状态行为
    #endregion




    #region  扩展
    /// <summary>
    /// 自动根据动画覆盖情况获取最大连击数
    /// </summary>
    public void SetMaxComboCount()
    {
        // 约定 攻击动画名称 是 攻击状态名 + combo + 1
        if (HasStateAnim(States.LightDoubleAttack.ToString() + 2))
        {
            lightDoubleAttackComboMax = 1;
        }
        if (HasStateAnim(States.LightDoubleAttack.ToString() + 3))
        {
            lightDoubleAttackComboMax = 2;
        }
        if (HasStateAnim(States.HeavyDoubleAttack.ToString() + 2))
        {
            heavyDoubleAttackComboMax = 1;
        }
        if (HasStateAnim(States.HeavyDoubleAttack.ToString() + 3))
        {
            heavyDoubleAttackComboMax = 2;
        }
    }

    //todo 可以简单的交换动画控制器 来切换所有动画，需要保持动画名统一
    public bool HasStateAnim(States _state) => HasStateAnim(_state.ToString());
    public bool HasStateAnim(string _stateName)
    {
        AnimatorOverrideController animatorOverrideController = anim.runtimeAnimatorController as AnimatorOverrideController;

        if (animatorOverrideController != null)
        {
            List<System.Collections.Generic.KeyValuePair<AnimationClip, AnimationClip>> overrides = new();
            animatorOverrideController.GetOverrides(overrides);
            foreach (var entry in overrides)
            {
                if (entry.Key.name == _stateName)
                {
                    if (entry.Value == null)
                    {
                        // 这个动画没有被覆盖
                        return false;
                    }
                    else
                    {
                        // 这个动画被覆盖了
                        return true;
                    }
                }
            }
        }
        return false;
    }

    #endregion


    #region  简写
    /// <summary>
    /// 基于条件的 异步
    /// 所有会被打断的逻辑都在这里处理
    /// </summary>
    /// <param name="action"></param>
    public async UniTask StarTaskWithTokenByUntil(Func<bool> action, Action callback = null)
    {
        var cancellationTokenSource = new CancellationTokenSource();
        tempTokenSources.Add(cancellationTokenSource);
        await UniTask.WaitUntil(action, cancellationToken: cancellationTokenSource.Token);
        tempTokenSources.Remove(cancellationTokenSource);
        callback?.Invoke();
    }

    public Vector2 LightShakePower => new Vector2(stats.lightPower.x * facingDir, stats.lightPower.y);
    public Vector2 HeavyShakePower => new Vector2(stats.heavyPower.x * facingDir, stats.heavyPower.y);

    #endregion



    #region  处理素材
    public Vector3 GetRealPos()
    {
        return transform.position + spriteOffset;
    }

    //获取图片的宽高
    public Vector2 GetSpriteSize()
    {
        return sr.sprite.bounds.size;
    }
    public float SpriteWidth => sr.sprite.bounds.size.x;
    public float SpriteHeight => sr.sprite.bounds.size.y;
    #endregion
}
